#pragma once

#include <string>
#include <functional>

#include "log.hpp"
extern Log log;

#include "socket.hpp"

class UDP_server
{
public:
    typedef std::function<bool(const std::string&, const std::string&, uint16_t)> func_t;
    typedef UDP_server self;
public:
    UDP_server()
        : _is_running(false)
    {}
private:
    UDP_server(const self&) = delete;
    self& operator=(const self&) = delete;
public:
    void init(uint16_t port, const std::string& ip = "0.0.0.0")
    {
        _sockfd.Create(SOCK_DGRAM);
        _sockfd.Bind(port, ip);
    }

    void run(func_t func)
    {
        _is_running = true;
        while (_is_running)
        {
            char inbuffer[1024] = { 0 };
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            ssize_t n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);
            if (n < 0)
            {
                log(Warning, "recvfrom error, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }

            uint16_t client_port = ntohs(client.sin_port);
            std::string client_ip = inet_ntoa(client.sin_addr);
            inbuffer[n] = 0;
            std::string info = inbuffer;

            _is_running = func(info, client_ip, client_port);
        }
    }

    ~UDP_server()
    {
        _sockfd.Close();
    }
private:
    Socket _sockfd;
    bool _is_running;
};